package com.aerfafish.spider.controller;


import com.aerfafish.spider.graph.GraphUpdater;
import com.aerfafish.spider.neo4j.dao.Fund;
import com.aerfafish.spider.neo4j.dao.FundHoldShare;
import com.aerfafish.spider.neo4j.dao.Share;
import com.aerfafish.spider.neo4j.spider.service.FundService;
import com.aerfafish.spider.neo4j.spider.service.FundShareRelationService;
import com.aerfafish.spider.neo4j.spider.service.ShareService;
import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api")
@Slf4j
public class GraphController {

    @Autowired
    GraphUpdater graphUpdater;

    @Autowired
    ShareService shareService;

    @Autowired
    FundService fundService;

    @Autowired
    FundShareRelationService fundShareService;

    @RequestMapping("/update/all_share")
    public ResponseEntity<?> updateAllShare() {
        List<String> shareCodes = shareService.queryAllShareByCode();
        try {
            for (String shareCode : shareCodes) {
                graphUpdater.updateShare(shareCode);
            }
        } catch (Exception e) {
            HttpStatus status = HttpStatus.valueOf(701);
            return new ResponseEntity<>(e.getMessage(), status);
        }
        HttpStatus status = HttpStatus.valueOf(200);
        return new ResponseEntity<>("success", status);

    }

    @RequestMapping("/update/all_fund")
    public ResponseEntity<?> updateAllFund() {
        List<String> fundCodes = fundService.queryAllFund();
        try {
            for (String fundCode : fundCodes) {
                graphUpdater.updateFund(fundCode);
            }
        } catch (Exception e) {
            HttpStatus status = HttpStatus.valueOf(701);
            return new ResponseEntity<>(e.getMessage(), status);
        }
        HttpStatus status = HttpStatus.valueOf(200);
        return new ResponseEntity<>("success", status);

    }

    @RequestMapping("/update/fund/{beginCode}/{endCode}")
    public ResponseEntity<?> updateSpecifiedFund(@PathVariable("beginCode") Integer beginCode,
                                                 @PathVariable("endCode") Integer endCode) {
        try {
            for(int i = beginCode; i < endCode; i++) {
                String fundCode = "" + i;
                while (fundCode.length() < 6) {
                    fundCode = "0".concat(fundCode);
                }
                graphUpdater.updateFund(fundCode);
            }
        } catch (Exception e) {
            HttpStatus status = HttpStatus.valueOf(701);
            return new ResponseEntity<>(e.getMessage(), status);
        }
        HttpStatus status = HttpStatus.valueOf(200);
        return new ResponseEntity<>("success", status);

    }

    @RequestMapping("/query/all_risk_fund/{threshold}")
    public ResponseEntity<?> queryAllRiskFund(@PathVariable("threshold") Float threshold) {
        if (threshold == null) {
            threshold = 0F;
        }
        Map <String, Point> nodes = new HashMap<>();
        List<Link> links = new ArrayList<>();
        List<FundHoldShare> fundHoldShares = fundShareService.queryRiskFund();
        for (FundHoldShare fundHoldShare : fundHoldShares) {
            Share share = fundHoldShare.getShare();
            Fund fund = fundHoldShare.getFund();
            Long assetSize = fund.getAssetSize();
            Float v = (share.getIncRate() * share.getLatestValue() * -1 / 100 * fundHoldShare.getSharesNum()) / assetSize;
            if (v > threshold) {
                Point fundPoint = new Point();
                Point sharePoint = new Point();
                Link link = new Link();
                fundPoint.setId(fund.getCode());
                fundPoint.setSymbolSize(10F);
                fundPoint.setName(fund.getCode());
                fundPoint.setValue(Float.toString(v));
                fundPoint.setCategory(0);
                sharePoint.setName(share.getShareName());
                sharePoint.setId(share.getMarket()+share.getCode());
                sharePoint.setSymbolSize(10F);
                sharePoint.setValue(share.getIncRate()/100 + "");
                sharePoint.setCategory(1);
                link.setSource(share.getMarket()+share.getCode());
                link.setTarget(fund.getCode());
                nodes.put(fund.getCode(), fundPoint);
                nodes.put(share.getMarket()+share.getCode(), sharePoint);
                links.add(link);
            }
        }
        List<Point> points = new ArrayList<>(nodes.values());
        Graph graph = new Graph();
        graph.setNodes(points);
        graph.setLinks(links);
        List<Categories> categories = new ArrayList<>();
        categories.add( new Categories("基金"));
        categories.add( new Categories("股票"));
        graph.setCategories(categories);
        HttpStatus status = HttpStatus.valueOf(200);
        return new ResponseEntity<>(JSON.toJSONString(graph), status);
    }

    @RequestMapping("/query/all_risk_fund")
    public ResponseEntity<?> queryAllRiskFund() {
        Float threshold = 0F;
        Map <String, Point> nodes = new HashMap<>();
        List<Link> links = new ArrayList<>();
        List<FundHoldShare> fundHoldShares = fundShareService.queryRiskFund();
        for (FundHoldShare fundHoldShare : fundHoldShares) {
            Share share = fundHoldShare.getShare();
            Fund fund = fundHoldShare.getFund();
            Long assetSize = fund.getAssetSize();
            Float v = (share.getIncRate() * share.getLatestValue() * -1 / 100 * fundHoldShare.getSharesNum()) / assetSize;
            if (v > threshold) {
                Point fundPoint = new Point();
                Point sharePoint = new Point();
                Link link = new Link();
                fundPoint.setId(fund.getCode());
                fundPoint.setSymbolSize(10F);
                fundPoint.setName(fund.getCode());
                fundPoint.setValue(Float.toString(v));
                fundPoint.setCategory(0);
                sharePoint.setName(share.getShareName());
                sharePoint.setId(share.getMarket()+share.getCode());
                sharePoint.setSymbolSize(10F);
                sharePoint.setValue(share.getIncRate()/100 + "");
                sharePoint.setCategory(1);
                link.setSource(share.getMarket()+share.getCode());
                link.setTarget(fund.getCode());
                nodes.put(fund.getCode(), fundPoint);
                nodes.put(share.getMarket()+share.getCode(), sharePoint);
                links.add(link);
            }
        }
        List<Point> points = new ArrayList<>(nodes.values());
        Graph graph = new Graph();
        graph.setNodes(points);
        graph.setLinks(links);
        List<Categories> categories = new ArrayList<>();
        categories.add( new Categories("基金"));
        categories.add( new Categories("股票"));
        graph.setCategories(categories);
        HttpStatus status = HttpStatus.valueOf(200);
        return new ResponseEntity<>(JSON.toJSONString(graph), status);
    }

    @Data
    public class Point {
        String id;

        String name;

        String value;

        Float symbolSize;

        Integer category;
    }

    @Data
    public class Link {
        String source;

        String target;
    }

    @Data
    @AllArgsConstructor
    public class Categories {
        String name;
    }

    @Data
    public class Graph {
        List<Point> nodes;

        List<Link> links;

        List<Categories> categories;
    }
}
